/* $Id: DJudgeUtils.java 133 2011-08-26 12:01:00Z altdotua@gmail.com $ */

package alt.djudge.frontend.server.servlets;

import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.net.URLEncoder;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import alt.djudge.frontend.server.datatypes.AbstractEntry;
import alt.djudge.frontend.server.datatypes.ContestProblemEntry;
import alt.djudge.frontend.server.datatypes.LanguageEntry;
import alt.djudge.frontend.server.datatypes.ProblemEntry;
import alt.djudge.frontend.server.datatypes.SubmissionDetailsEntry;
import alt.djudge.frontend.server.datatypes.SubmissionEntry;
import alt.djudge.frontend.server.datatypes.SubmissionFull;
import alt.djudge.frontend.server.datatypes.UserEntry;
import alt.djudge.frontend.server.models.ContestProblemsModel;
import alt.djudge.frontend.server.models.CoreInterface;
import alt.djudge.frontend.server.models.LanguagesModel;
import alt.djudge.frontend.server.models.ProblemsModel;
import alt.djudge.frontend.server.models.SubmissionsModel;
import alt.djudge.frontend.server.utils.Linker;


public class DJudgeUtils
{
	private static final Logger log = Logger.getLogger(DJudgeUtils.class);
	
	public static String quote(Object t)
	{
		return "\"" + (t != null ? t.toString() : "") + "\"";
	}
	
	public static void printDJudgeXml(ServletOutputStream rr) throws IOException
	{
		SubmissionFull s = SubmissionsModel.getDJudgeTask();
		rr.println("<?xml version='1.0' encoding='UTF-8'?>");
		rr.println("<DJudgeTask ");
		if (null != s)
		{
			try
			{
				PrintWriter r = new PrintWriter(new OutputStreamWriter(rr, "UTF8"), true);
				SubmissionEntry se = s.getSubmissionEntry();
				r.println("id=" + quote(se.getId().toString()));
				ContestProblemEntry cpe = ContestProblemsModel.getEntry(se.getContestProblemId());
				ProblemEntry p = ProblemsModel.getEntry(cpe.getProblemId());
				r.println("contest_id=" + quote(p.getDjudgeContest()));
				r.println("problem_id=" + quote(p.getDjudgeProblem()));
				r.println("time_limit=" + quote(p.getTimeLimit()));
				r.println("memory_limit=" + quote(p.getMemoryLimit()));
				LanguageEntry l = LanguagesModel.getEntry(se.getLanguageId());
				r.println("language_id=" + quote(l.getDjudgeId()));
				r.println("first_test_only=" + quote(se.getFlagFirstTestOnly()));
				String sourceCode = new String(s.getSubmissionDetailsEntry().getSourceCode().getBytes());
				System.out.println(sourceCode);
				r.println("source_code=" + quote(StringEscapeUtils.escapeXml(sourceCode.replace('\n', (char)234))));
				se.setDjudgeFlag(-1);
				se.setDjudgeFetchDate(new Date());
				se.makePersistent();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		rr.println("/>");
	}
	
	public static void putXml(String id, String xml)
	{
		log.debug("Receiver " + id + " \n" + xml + "\n");
		String xmlDecoded = "";
		xmlDecoded = xml;
		SubmissionEntry s = SubmissionsModel.getSubmission(Long.parseLong(id));
		SubmissionDetailsEntry sd = SubmissionsModel.getSubmissionDetails(s.getSubmissionDetailsId());
		sd.setXmlReport(xmlDecoded);
		sd.makePersistent();
		Document doc = getDocumentFromString(xmlDecoded);
		Element elem = doc.getDocumentElement();
		String judgement = elem.getAttribute("result");
		s.setJudgement(judgement);
		s.setDjudgeFetchDate(new Date());
		s.setDjudgeFlag(1);
		System.out.println(judgement);
		
		if ("CE".equals(judgement))
		{
			s.setActive(false);
			s.decrementPendingsCount();
		}
		
		if (s.getFlagFirstTestOnly() == false && !"CE".equals(judgement))
		{
			/* Judgement data */
			String maxMemoryStr = elem.getAttribute("max-memory");
			String maxTimeStr = elem.getAttribute("max-time");
			String scoreStr = elem.getAttribute("score");
			String wrongTestStr = elem.getAttribute("wrong-test");
			s.setMaxMemoryUsed(Integer.parseInt(maxMemoryStr));
			s.setMaxTimeUsed(Integer.parseInt(maxTimeStr));
			s.setScore(Integer.parseInt(scoreStr));
			s.setWrongTestNumber(Integer.parseInt(wrongTestStr));
			/* Scores */
			//s.addScores();
		}
		s.makePersistent();
	}
	
	public static Document getDocumentFromString(String xmlString)
	{
		DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
		DocumentBuilder docBuilder;
		try
		{
			docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(new ByteArrayInputStream(xmlString.getBytes()));
			return doc;
		}
		catch (ParserConfigurationException e)
		{
			e.printStackTrace();
		}
		catch (SAXException e)
		{
			e.printStackTrace();
			
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		return null;
	}
	
	public static String generateTable(HttpServletRequest req, HttpServletResponse resp, Class<? extends AbstractEntry> cl, CoreInterface<? extends AbstractEntry> core) throws Exception
	{
		AbstractEntry classEntry = cl.newInstance();
		
		StringBuffer sb = new StringBuffer();
		sb.append("<table border=\"1\" align=\"center\">");
		sb.append("<tr>");
		
		sb.append("<th colspan=\"3\">Actions</th>");
		
		for (Field field : cl.getDeclaredFields())
			if (classEntry.isDataFieldName(field.getName()))
			{
				sb.append("<th>" + field.getName() + "</th>");
			}
		if (classEntry.getClass().equals(UserEntry.class))
		{
			sb.append("<th>D</th>");
		}
		sb.append("</tr>");
		
		List<? extends AbstractEntry> entries = core.getAllEntries();
		for (AbstractEntry entry: entries)
		{
			sb.append("<tr>");
				sb.append("<td>");
					sb.append("<a href=\"");
						sb.append(Linker.link(classEntry.getServletPath() + "?action=delete&id=" + entry.getId() + "&return=" + URLEncoder.encode(req.getRequestURL().toString(), AbstractDataServlet.defaultEncoding)));
					sb.append("\">Del</a>");
				sb.append("</td>");
				sb.append("<td>");
					sb.append("<a href=\"");
						sb.append(req.getRequestURL() + "?id=" + entry.getId());
				sb.append("\">Edt</a>");
			sb.append("</td>");
			sb.append("<td>");
				sb.append("<a href=\"");
					sb.append(Linker.link(classEntry.getServletPath() + "?action=copy&id=" + entry.getId() + "&return=" + URLEncoder.encode(req.getRequestURL().toString(), AbstractDataServlet.defaultEncoding)));
				sb.append("\">Cpy</a>");
			sb.append("</td>");
			for (Field field : cl.getDeclaredFields())
				if (classEntry.isDataFieldName(field.getName()))
				{
					sb.append("<td>" + (!field.getName().equals("statement") ? entry.getFieldValue(field) : "-") + "</td>");
				}
			if (classEntry.getClass().equals(UserEntry.class))
			{
				sb.append("<th>http://192.168.53.194/djudge-web/olymp2011/</th>");
				sb.append("<th><a href=\"" + Linker.link("admin/user.jsp?user_id=" + entry.getId()) +"\">...</a></th>");
			}
			sb.append("</tr>");
		}
		sb.append("</table>");
		return sb.toString();
	}
	
	public static String generateTable(HttpServletRequest req, HttpServletResponse resp, Class<? extends AbstractEntry> cl, CoreInterface<AbstractEntry> core, String mod) throws Exception
	{
		AbstractEntry classEntry = cl.newInstance();
		
		StringBuffer sb = new StringBuffer();
		sb.append("<table border=\"1\" align=\"center\">");
		sb.append("<tr>");
		
		sb.append("<th colspan=\"3\">Actions</th>");
		
		for (Field field : cl.getDeclaredFields())
			if (classEntry.isDataFieldName(field.getName()))
			{
				sb.append("<th>" + field.getName() + "</th>");
			}
		sb.append("</tr>");
		
		List<? extends AbstractEntry> entries = core.getAllEntries();
		for (AbstractEntry entry: entries)
		{
			sb.append("<tr>");
				sb.append("<td>");
					sb.append("<a href=\"");
						sb.append(Linker.link(classEntry.getServletPath() + "?action=delete&id=" + entry.getId() + "&return=" + URLEncoder.encode(req.getRequestURL().toString(), AbstractDataServlet.defaultEncoding)));
					sb.append("\">Del</a>");
				sb.append("</td>");
				sb.append("<td>");
					sb.append("<a href=\"");
						sb.append(req.getRequestURL() + "?id=" + entry.getId());
				sb.append("\">Edt</a>");
			sb.append("</td>");
			sb.append("<td>");
				sb.append("<a href=\"");
					sb.append(Linker.link(classEntry.getServletPath() + "?action=copy&id=" + entry.getId() + "&return=" + URLEncoder.encode(req.getRequestURL().toString(), AbstractDataServlet.defaultEncoding)));
				sb.append("\">Cpy</a>");
			sb.append("</td>");
			for (Field field : cl.getDeclaredFields())
				if (classEntry.isDataFieldName(field.getName()))
				{
					sb.append("<td>" + (!field.getName().equals("statement") ? entry.getFieldValue(field) : "-") + "</td>");
				}
			sb.append("</tr>");
		}
		sb.append("</table>");
		return sb.toString();
	}
}
